
/*
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-3.0+
 * License-Filename: LICENSE
 *
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "splay-tree.h"
#include "main.h"
#include "parse.h"
#include "parsedot.h"
#include "uniqstring.h"
#include "color.h"
#include "options.h"

/* */
int is_a_dotnodedefault(struct usubg *subg)
{
	int tmpi = 0;
	char *tmps = NULL;
	char *fontsize = NULL;
	int fontsize_set = 0;
	char *fontname = NULL;
	int fontname_set = 0;
	char *tmpurl = NULL;
	int tmpurl_set = 0;
	int bcolor = 0;
	int bcolor_set = 0;
	char *bcolorstr = NULL;
	int cscode = 0;
	int cscode_set = 0;
	char *csstr = NULL;
	int shapecode = 0;
	int shapecode_set = 0;
	int fillcolorn = 0;
	int fillcolor = 0;
	int fillcolor_set = 0;
	char *flabel = NULL;
	int label_set = 0;
	char *styles = NULL;
	int style_set = 0;
	int stylefilled_set = 0;

	if (token != DOT_NODE) {
		return (0);
	}

	if (subg) {
		/* */
	} else {
		/* */
	}
	/* [ */
	token = dot_lex();
	if (token != DOT_BRACKETO) {
		parser_error_string = "expected [ at node default";
		return (1);
	}

	fontname = NULL;
	fontname_set = 0;
	fontsize = NULL;
	fontsize_set = 0;
	tmpurl = NULL;
	tmpurl_set = 0;
	bcolor = 0;
	bcolor_set = 0;
	bcolorstr = NULL;
	cscode = 0;
	cscode_set = 0;
	csstr = NULL;
	shapecode = 0;
	shapecode_set = 0;
	fillcolorn = 0;
	fillcolor = 0;
	fillcolor_set = 0;
	flabel = NULL;
	label_set = 0;
	styles = NULL;
	style_set = 0;
	stylefilled_set = 0;

	/* keep on reading the node default options
	 * color colorscheme comment distortion fillcolor fixedsize fontcolor fontname
	 * fontsize group height id image imagescale label labelloc layer margin nojustify
	 * orientation penwidth peripheries pin pos rects regular root samplepoints shape
	 * shapefile showboxes sides skew sortv style target tooltip vertices width z
	 */

	for (;;) {
		token = dot_lex();
		if (token == 0) {
			parser_error_string = "un-expected end-of-file at node default";
			return (0);
		}
		/* dot allows space, comma and ';' between the elements in node attributes list */
		if (token == DOT_SEMIC) {
			/* skip optional semicomma */
			token = dot_lex();
		}

		if (token == DOT_COMMA) {
			/* skip optional comma */
			token = dot_lex();
		}
		if (token == DOT_BRACKETC) {
			/* end of options */
			break;
		}
		/*
		 * here start the options
		 */
		if (token == DOT_CHAR) {
			/* 3d-position, depreciated, double number z opt */

			/* z opt */
			if (strcmp(lastchar, "z") == 0) {

			} else {
				/* unknown */
			}
		} else if (token == DOT_ID) {
			/* 1) begin of node default settings */
			if (strcmp(lastid, "URL") == 0) {
				/* URL and href set default url for node */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default URL";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_STRING) {
					/* laststring has the url */
					tmpurl = laststring;
				} else if (token == DOT_ID) {
					tmpurl = lastid;
				} else {
					parser_error_string = "expected url-string at node default URL";
					return (1);
				}
				/* check for "" */
				if (strlen(tmpurl) == 0) {
					tmpurl = NULL;
				}
				tmpurl_set = 1;
			} else if (strcmp(lastid, "area") == 0) {
				/* node area, area=2.0 (double), select preferred node area for patchwork */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default area";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "color") == 0) {
				/* if fillcolor is not set, node is filled with color setting.
				 * if fillcolor is set, color is used for border color.
				 */
				/* color of the graphic of a node or a colorlist for a gradient */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default color";
					return (1);
				}
				token = dot_lex();
				/* color arg can be a color list, number, id, string */
				if (token == DOT_NUM) {
					/* colorscheme number fixme */
					bcolor_set = 0;
				} else {
					if (token == DOT_STRING) {
						bcolorstr = laststring;
					} else if (token == DOT_ID) {
						bcolorstr = lastid;
					} else {
						parser_error_string = "expected colorname at node color";
						return (1);
					}
					bcolor = colorcode(bcolorstr);
					if (bcolor == -1) {
						bcolorstr = NULL;
						bcolor_set = 0;
					} else {
						bcolor_set = 1;
					}
				}
			} else if (strcmp(lastid, "colorscheme") == 0) {
				/* color scheme to use with numbered colors, see bison graph data */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default colorscheme";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_STRING) {
					csstr = laststring;
				} else if (token == DOT_ID) {
					csstr = lastid;
				} else {
					parser_error_string = "expected name at node default colorscheme";
					return (1);
				}
				cscode = colorschemecode(csstr);
				if (cscode) {
					cscode_set = 1;
				}
			} else if (strcmp(lastid, "comment") == 0) {
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default comment";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "distortion") == 0) {
				/* distortion factor for polygon shape, +/- double number distortion="0.936354" */

				/* distortion="0.936354" */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default distortion";
					return (1);
				}
				token = dot_lex();

			} else if (strcmp(lastid, "fillcolor") == 0) {
				/* background color of node or white if unknown */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default fillcolor";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_NUM) {
					fillcolorn = atoi(lastnum);	/* fixme should do better here XXX strtod() */
					/* colorscheme color earlier defined? */
					if (cscode_set) {
						fillcolor = colornscode(fillcolorn, cscode);
					} else {
						if (subg == NULL) {
							fillcolor = colornscode(fillcolorn, nd_cs);
						} else {
							fillcolor = colornscode(fillcolorn, subg->nd_cs);
						}
					}
					/* ignore unknown color */
					if (fillcolor == -1) {
						fillcolor_set = 0;
					} else {
						fillcolor_set = 1;
					}
				} else {
					if (token == DOT_STRING) {
						fillcolor = colorcode(laststring);
						if (fillcolor == -1) {
							/* white node background color */
							fillcolor_set = 0;
						} else {
							fillcolor_set = 1;
						}
					} else if (token == DOT_ID) {
						/* GCC7 uses lightgrey but that should be LightGrey */
						fillcolor = colorcode(lastid);
						if (fillcolor == -1) {
							/* white node background color */
							fillcolor_set = 0;
						} else {
							fillcolor_set = 1;
						}
					} else {
						parser_error_string = "expected color at node default fillcolor option";
						return (0);
					}
				}
			} else if (strcmp(lastid, "fixedsize") == 0) {
				/* false/true/any/shape, size of node and the label text */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default fixedsize";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "fontcolor") == 0) {
				/* color for text */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default fontcolor";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "fontname") == 0) {
				/* name of font text */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default fontname";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_STRING) {
					fontname = laststring;
				} else if (token == DOT_ID) {
					fontname = lastid;
				} else if (token == DOT_CHAR) {
					fontname = lastchar;
				} else {
					parser_error_string = "expected string or number at node default fontname";
					return (1);
				}
				if (strlen(fontname) == 0) {
					fontname = NULL;
				} else {
					fontname_set = 1;
				}
			} else if (strcmp(lastid, "fontsize") == 0) {
				/* size of font text */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default fontsize";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_STRING) {
					fontsize = laststring;
				} else if (token == DOT_NUM) {
					fontsize = lastnum;
				} else {
					parser_error_string = "expected string or number at node default fontsize";
					return (1);
				}

				fontsize_set = 1;
				/* use gtk default at fontsize=0 or fontsize="" */
				if (strlen(fontsize) == 0) {
					fontsize_set = 0;
					fontsize = NULL;
				}else
				if (atoi(fontsize) <= 0) {	/* XXXX should be strtod() */
					fontsize_set = 0;
					fontsize = NULL;
				}
			} else if (strcmp(lastid, "gradientangle") == 0) {
				/* angle of fill, int number */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default gradientangle";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "group") == 0) {
				/* endpoint of edge grouping, string */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default group";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "height") == 0) {
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default height";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "href") == 0) {
				/* same as URL */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default href";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_STRING) {
					/* laststring has the url */
					tmpurl = laststring;
				} else if (token == DOT_ID) {
					tmpurl = lastid;
				} else {
					parser_error_string = "expected url-string at node default URL";
					return (1);
				}
				/* check for "" */
				if (strlen(tmpurl) == 0) {
					tmpurl = NULL;
				}
				tmpurl_set = 1;
			} else if (strcmp(lastid, "id") == 0) {
				/* uniq id for node optionally supplied, escstring */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default id";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "image") == 0) {
				/* image for node */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default image";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "imagepos") == 0) {
				/* how image is positioned inside node shape */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default image";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "imagescale") == 0) {
				/* scale image true/false */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default imagescale";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "label") == 0) {
				/* label text of node */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default label";
					return (1);
				}
				token = dot_lex();
				/* default label to use to save as raw string with esc chars embedded */
				if (token == DOT_STRING) {
					flabel = laststring;
					/* check for "" */
					if (strlen(laststring) == 0) {
						/* because of forgotten reasons a "" is replaced with a space */
						flabel = uniqstring((char *)" ");
					}
					/* option to use name of node instead of label text */
					if (option_nodenames) {
						flabel = NULL;
					}
					if (flabel) {
						label_set = 1;
					}
				} else if (token == DOT_ID) {
					flabel = lastid;
					if (strlen(lastid) == 0) {
						flabel = NULL;
					}
					if (option_nodenames) {
						flabel = NULL;
					}
					if (flabel) {
						label_set = 2;
					}
				} else if (token == DOT_NUM) {
					flabel = lastnum;
					if (strlen(lastnum) == 0) {
						flabel = NULL;
					}
					if (option_nodenames) {
						flabel = NULL;
					}
					if (flabel) {
						label_set = 3;
					}
				} else if (token == DOT_HTML) {
					/* html string is interpreted, just as record string */
					flabel = lasthtml;
					label_set = 4;
				} else if (token == DOT_CHAR) {
					flabel = lastchar;
					label_set = 5;
				} else {
					parser_error_string = "expected string at node label option";
					return (0);
				}
				if (flabel) {
					/* "" is no-label */
					if (strlen(flabel) == 0) {
						label_set = 0;
					}
				}
			} else if (strcmp(lastid, "labelloc") == 0) {
				/* vertical placement of label text */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default labelloc";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "layer") == 0) {
				/* layer in which node is present */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default layer";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "margin") == 0) {
				/* space around node text label, double example "0.02,0" */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default margin";
					return (1);
				}
				token = dot_lex();
				/* must be number */
				/* margin with optional x,y direction in pixels around label text %lf,%lf */
				if (token == DOT_STRING) {
					/* x,y */
				} else if (token == DOT_NUM) {
					/* only x dir */
				} else {
					parser_error_string = "expected numbers at node default margin";
					return (1);
				}
			} else if (strcmp(lastid, "nojustify") == 0) {
				/* justify label text true/false */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default nojustify";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "ordering") == 0) {
				/* in/out edge ordering, string, in/out */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default ordening";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "orientation") == 0) {
				/* rotate shape in double angle, 0..360 */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default orientation";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "pencolor") == 0) {
				/* color to draw lines */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default pencolor";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "penwidth") == 0) {
				/* double number to draw thickness of lines */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default penwidth";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "peripheries") == 0) {
				/* number of peripheries in a shape, int */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default peripheries";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "pin") == 0) {
				/* pin position, boolean, not dot but neato */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default pin";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "pos") == 0) {
				/* position of node in points */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default pos";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "rects") == 0) {
				/* rectangles for fields in record in points, %f,%f,%f,%f */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default rects";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "regular") == 0) {
				/* force polygon to be regular, true/false */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default regular";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "root") == 0) {
				/* specify root of layout, not dot but circo */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default root";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "samplepoints") == 0) {
				/* number of point for a node at shape circle, ellipse, integer */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default samplepoints";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "shape") == 0) {
				/* shape of node to draw */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default shape";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_ID) {
					tmps = lastid;
				} else if (token == DOT_STRING) {
					tmps = laststring;
				} else {
					parser_error_string = "unknown node shape at node default shape";
					return (1);
				}
				tmpi = is_a_dot_shape_name(tmps);
				/* error when not found */
				if (tmpi == 0) {
					parser_error_string = "expected id or string at node default shape";
					return (1);
				}
				shapecode_set = 1;
				/* adjust to shape */
				switch (tmpi) {
				case DSHAPE_ASSEMBLY:	/* "assembly" */
					shapecode = 0;
					break;
				case DSHAPE_BOX:	/* "box" */
					shapecode = NSHAPE_BOX;
					break;
				case DSHAPE_BOX3D:	/* "box3d" */
				case DSHAPE_CDS:	/* "cds" */
					shapecode = 0;
					break;
				case DSHAPE_CIRCLE:	/* "circle" */
					shapecode = NSHAPE_CIRCLE;
					break;
				case DSHAPE_COMPONENT:	/* "component" */
				case DSHAPE_CYLINDER:	/* "cylinder" */
				case DSHAPE_DIAMOND:	/* "diamond" */
				case DSHAPE_DOUBLECIRCLE:	/* "doublecircle" */
				case DSHAPE_DOUBLEOCTAGON:	/* "doubleoctagon" */
				case DSHAPE_EGG:	/* "egg" */
					shapecode = 0;
					break;
				case DSHAPE_ELLIPSE:	/* "ellipse" */
					shapecode = NSHAPE_ELLIPS;
					break;
				case DSHAPE_FIVEPOVERHANG:	/* "fivepoverhang" */
				case DSHAPE_FOLDER:	/* "folder" */
				case DSHAPE_HEXAGON:	/* "hexagon" */
				case DSHAPE_HOUSE:	/* "house" */
				case DSHAPE_INSULATOR:	/* "insulator" */
				case DSHAPE_INVHOUSE:	/* "invhouse" */
				case DSHAPE_INVTRAPEZIUM:	/* "invtrapezium" */
				case DSHAPE_INVTRIANGLE:	/* "invtriangle" */
				case DSHAPE_LARROW:	/* "larrow" */
				case DSHAPE_LPROMOTOR:	/* "lpromoter" */
				case DSHAPE_MCIRCLE:	/* "Mcircle" */
				case DSHAPE_MDIAMOND:	/* "Mdiamond" */
				case DSHAPE_MSQUARE:	/* "Msquare" */
				case DSHAPE_NONE:	/* "none" */
				case DSHAPE_NOTE:	/* "note" */
				case DSHAPE_NOVERHANG:	/* "noverhang" */
				case DSHAPE_OCTAGON:	/* "octagon" */
				case DSHAPE_OVAL:	/* "oval" */
				case DSHAPE_PARALLELOGRAM:	/* "parallelogram" */
				case DSHAPE_PENTAGON:	/* "pentagon" */
				case DSHAPE_PLAIN:	/* "plain" */
				case DSHAPE_PLAINTEXT:	/* "plaintext" */
				case DSHAPE_POINT:	/* "point" */
				case DSHAPE_POLYGON:	/* "polygon" */
				case DSHAPE_PRIMERSITE:	/* "primersite" */
				case DSHAPE_PROMOTER:	/* "promoter" */
				case DSHAPE_PROTEASESITE:	/* "proteasesite" */
				case DSHAPE_PROTEINSTAB:	/* "proteinstab" */
				case DSHAPE_RARROW:	/* "rarrow" */
					shapecode = 0;
					break;
				case DSHAPE_RECORD:	/* special "record" */
					shapecode = NSHAPE_RECORD;
					break;
				case DSHAPE_RECT:	/* "rect" */
				case DSHAPE_RECTANGLE:	/* "rectangle" */
				case DSHAPE_RESTRICTIONSITE:	/* "restrictionsite" */
				case DSHAPE_RIBOSITE:	/* "ribosite" */
				case DSHAPE_RNASTAB:	/* "rnastab" */
				case DSHAPE_RPROMOTER:	/* "rpromoter" */
				case DSHAPE_SEPTAGON:	/* "septagon" */
				case DSHAPE_SIGNATURE:	/* "signature" */
				case DSHAPE_SQUARE:	/* "square" */
				case DSHAPE_STAR:	/* "star" */
				case DSHAPE_TAB:	/* "tab" */
				case DSHAPE_TERMINATOR:	/* "terminator" */
				case DSHAPE_THREEPOVERHANG:	/* "threepoverhang" */
				case DSHAPE_TRAPEZIUM:	/* "trapezium" */
				case DSHAPE_TRIANGLE:	/* "triangle" */
				case DSHAPE_TRIPLEOCTAGON:	/* "tripleoctagon" */
				case DSHAPE_UNDERLINE:	/* "underline" */
				case DSHAPE_UTR:	/* "utr" */
				default:
					/* should not happen */
					shapecode = 0;
					break;
				}
				/* */
			} else if (strcmp(lastid, "shapefile") == 0) {
				/* shapefile="test.ps" in a box area is depreciated */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default shapefile";
					return (1);
				}
				token = dot_lex();
				if (token == DOT_ID) {
					tmps = lastid;
				} else if (token == DOT_STRING) {
					tmps = laststring;
				} else {
					parser_error_string = "expected filename string at node default shapefile";
					return (1);
				}
				/* shapefile="test.ps" is depreciated " */
			} else if (strcmp(lastid, "showboxes") == 0) {
				/* print boxes, postscript only, value 0,1,2 */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default showboxes";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "sides") == 0) {
				/* number of sides if shape is polygon, int, default 4 */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default sides";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "skew") == 0) {
				/* skew factor for shape polygon, double -100..+100 */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default skew";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "sortv") == 0) {
				/* array packing order, int */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default sortv";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "style") == 0) {
				/* style setting */
				/* style=item(,item)*
				 * style="" is same as no-style-argument
				 * can haven multiple params
				 * style does influence color,fillcolor
				 * style can be bold which is same as setpenwidth
				 * style for nodes is different from edges, clusters
				 * see docs, complicated. XXX
				 */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default style";
					return (1);
				}
				token = dot_lex();
				/* style mode can be "" */
				if (token == DOT_STRING) {
					styles = laststring;
				} else if (token == DOT_ID) {
					styles = lastid;
				} else {
					parser_error_string = "expected style code at node style";
					return (1);
				}
				if (strlen(styles) == 0) {
					/* "" is same as no style parameter */
					style_set = 0;
				} else {
					/* parse here the components of the style string XXX fixme */
					style_set = 1;
					if (strchr(styles, ',') || strchr(styles, '(')) {
						/* assume to be be arg,arg or arg(arg) */
					} else {
						if (strcmp(styles, "filled") == 0) {
							stylefilled_set = 1;
						}
					}
				}

			} else if (strcmp(lastid, "target") == 0) {
				/* at url, svg only */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default target";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "tooltip") == 0) {
				/* tooltip svg only */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default tooltip";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "vertices") == 0) {
				/* polygonal node vertices, arg is pointlist seperated by spaces */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default vertices";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "width") == 0) {
				/* min. witdth of node, double */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default width";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "xlabel") == 0) {
				/* external label for node */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default xlabel";
					return (1);
				}
				token = dot_lex();
			} else if (strcmp(lastid, "xlp") == 0) {
				/* po. of ext. label in points */

				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at node default xlp";
					return (1);
				}
				token = dot_lex();
			} else {
				/* unknown id attribute value */
				/* = */
				token = dot_lex();
				if (token != DOT_IS) {
					parser_error_string = "expected = at unknown node default option (1)";
					return (1);
				}
				/* some unkown value for a unknown parameter */
				token = dot_lex();
			}
			/* 1) end of node default settings */
		} else {
			/* not char, not id */
			parser_error_string = "expected char or id at node default option";
			return (1);
		}
		/*
		 * end of the options
		 */
	}

	/* style=arg */
	if (style_set) {
		if (stylefilled_set) {
			if (subg == NULL) {
				nd_stylefilled = 1;
			} else {
				subg->nd_stylefilled = 1;
			}
		}
	}

	/* url of node */
	if (tmpurl_set) {
		if (subg == NULL) {
			nd_url = tmpurl;
		} else {
			subg->nd_url = tmpurl;
		}
	}

	/* node fill color */
	if (fillcolor_set) {
		if (subg == NULL) {
			nd_fillcolor = fillcolor;
		} else {
			subg->nd_fillcolor = fillcolor;
		}
	}

	/* node border color */
	if (bcolor_set) {
		if (subg == NULL) {
			nd_bcolor = bcolor;
		} else {
			subg->nd_bcolor = bcolor;
		}
	}

	/* color scheme */
	if (cscode_set) {
		if (subg == NULL) {
			nd_cs = cscode;
		} else {
			subg->nd_cs = cscode;
		}
	}

	/* code number of node shape or 0 for default */
	if (shapecode_set) {
		if (subg == NULL) {
			nd_shape = shapecode;
		} else {
			subg->nd_shape = shapecode;
		}
	}

	if (label_set) {
		if (subg == NULL) {
			nd_label = flabel;
			nd_labeltype = label_set;
		} else {
			subg->nd_label = flabel;
			subg->nd_labeltype = label_set;
		}
	}

	if (fontname_set) {
		if (subg == NULL) {
			nd_fontname = fontname;
		} else {
			subg->nd_fontname = fontname;
		}
	}

	if (fontsize_set) {
		if (subg == NULL) {
			nd_fontsize = fontsize;
		} else {
			subg->nd_fontsize = fontsize;
		}
	}

	/* oke */
	return (1);
}

/* is a known shape name */
int is_a_dot_shape_name(char *s)
{
	int ret = 0;
	if (strcmp("assembly", s) == 0) {
		ret = DSHAPE_ASSEMBLY;
	} else if (strcmp("box", s) == 0) {
		ret = DSHAPE_BOX;
	} else if (strcmp("box3d", s) == 0) {
		ret = DSHAPE_BOX3D;
	} else if (strcmp("cds", s) == 0) {
		ret = DSHAPE_CDS;
	} else if (strcmp("circle", s) == 0) {
		ret = DSHAPE_CIRCLE;
	} else if (strcmp("component", s) == 0) {
		ret = DSHAPE_COMPONENT;
	} else if (strcmp("cylinder", s) == 0) {
		ret = DSHAPE_CYLINDER;
	} else if (strcmp("diamond", s) == 0) {
		ret = DSHAPE_DIAMOND;
	} else if (strcmp("doublecircle", s) == 0) {
		ret = DSHAPE_DOUBLECIRCLE;
	} else if (strcmp("doubleoctagon", s) == 0) {
		ret = DSHAPE_DOUBLEOCTAGON;
	} else if (strcmp("egg", s) == 0) {
		ret = DSHAPE_EGG;
	} else if (strcmp("ellipse", s) == 0) {
		ret = DSHAPE_ELLIPSE;
	} else if (strcmp("fivepoverhang", s) == 0) {
		ret = DSHAPE_FIVEPOVERHANG;
	} else if (strcmp("folder", s) == 0) {
		ret = DSHAPE_FOLDER;
	} else if (strcmp("hexagon", s) == 0) {
		ret = DSHAPE_HEXAGON;
	} else if (strcmp("house", s) == 0) {
		ret = DSHAPE_HOUSE;
	} else if (strcmp("insulator", s) == 0) {
		ret = DSHAPE_INSULATOR;
	} else if (strcmp("invhouse", s) == 0) {
		ret = DSHAPE_INVHOUSE;
	} else if (strcmp("invtrapezium", s) == 0) {
		ret = DSHAPE_INVTRAPEZIUM;
	} else if (strcmp("invtriangle", s) == 0) {
		ret = DSHAPE_INVTRIANGLE;
	} else if (strcmp("larrow", s) == 0) {
		ret = DSHAPE_LARROW;
	} else if (strcmp("lpromoter", s) == 0) {
		ret = DSHAPE_LPROMOTOR;
	} else if (strcmp("Mcircle", s) == 0) {
		ret = DSHAPE_MCIRCLE;
	} else if (strcmp("Mdiamond", s) == 0) {
		ret = DSHAPE_MDIAMOND;
	} else if (strcmp("Msquare", s) == 0) {
		ret = DSHAPE_MSQUARE;
	} else if (strcmp("Mrecord", s) == 0) {
		/* special */
		ret = DSHAPE_RECORD;
	} else if (strcmp("none", s) == 0) {
		ret = DSHAPE_NONE;
	} else if (strcmp("note", s) == 0) {
		ret = DSHAPE_NOTE;
	} else if (strcmp("noverhang", s) == 0) {
		ret = DSHAPE_NOVERHANG;
	} else if (strcmp("octagon", s) == 0) {
		ret = DSHAPE_OCTAGON;
	} else if (strcmp("oval", s) == 0) {
		ret = DSHAPE_OVAL;
	} else if (strcmp("parallelogram", s) == 0) {
		ret = DSHAPE_PARALLELOGRAM;
	} else if (strcmp("pentagon", s) == 0) {
		ret = DSHAPE_PENTAGON;
	} else if (strcmp("plain", s) == 0) {
		ret = DSHAPE_PLAIN;
	} else if (strcmp("plaintext", s) == 0) {
		ret = DSHAPE_PLAINTEXT;
	} else if (strcmp("point", s) == 0) {
		ret = DSHAPE_POINT;
	} else if (strcmp("polygon", s) == 0) {
		ret = DSHAPE_POLYGON;
	} else if (strcmp("primersite", s) == 0) {
		ret = DSHAPE_PRIMERSITE;
	} else if (strcmp("promoter", s) == 0) {
		ret = DSHAPE_PROMOTER;
	} else if (strcmp("proteasesite", s) == 0) {
		ret = DSHAPE_PROTEASESITE;
	} else if (strcmp("proteinstab", s) == 0) {
		ret = DSHAPE_PROTEINSTAB;
	} else if (strcmp("rarrow", s) == 0) {
		ret = DSHAPE_RARROW;
	} else if (strcmp("record", s) == 0) {
		/* special */
		ret = DSHAPE_RECORD;
	} else if (strcmp("rect", s) == 0) {
		ret = DSHAPE_RECT;
	} else if (strcmp("rectangle", s) == 0) {
		ret = DSHAPE_RECTANGLE;
	} else if (strcmp("restrictionsite", s) == 0) {
		ret = DSHAPE_RESTRICTIONSITE;
	} else if (strcmp("ribosite", s) == 0) {
		ret = DSHAPE_RIBOSITE;
	} else if (strcmp("rnastab", s) == 0) {
		ret = DSHAPE_RNASTAB;
	} else if (strcmp("rpromoter", s) == 0) {
		ret = DSHAPE_RPROMOTER;
	} else if (strcmp("septagon", s) == 0) {
		ret = DSHAPE_SEPTAGON;
	} else if (strcmp("signature", s) == 0) {
		ret = DSHAPE_SIGNATURE;
	} else if (strcmp("square", s) == 0) {
		ret = DSHAPE_SQUARE;
	} else if (strcmp("star", s) == 0) {
		ret = DSHAPE_STAR;
	} else if (strcmp("tab", s) == 0) {
		ret = DSHAPE_TAB;
	} else if (strcmp("terminator", s) == 0) {
		ret = DSHAPE_TERMINATOR;
	} else if (strcmp("threepoverhang", s) == 0) {
		ret = DSHAPE_THREEPOVERHANG;
	} else if (strcmp("trapezium", s) == 0) {
		ret = DSHAPE_TRAPEZIUM;
	} else if (strcmp("triangle", s) == 0) {
		ret = DSHAPE_TRIANGLE;
	} else if (strcmp("tripleoctagon", s) == 0) {
		ret = DSHAPE_TRIPLEOCTAGON;
	} else if (strcmp("underline", s) == 0) {
		ret = DSHAPE_UNDERLINE;
	} else if (strcmp("utr", s) == 0) {
		ret = DSHAPE_UTR;
	} else {
		/* unknown node shape */
		ret = 0;
	}
	return (ret);
}

/* end */
